<?php
/**
 * Pageley_Util_File refers to a file on the file system and provided methods for
 * accessing information on files and manipulating them.
 * 
 * @package be.appcraft.util
 * @version $Revision: 1.1 $
 *
 * @author Stijn Van Bael
 * @since 1.0
 */
class Pageley_Util_File {
	
	/**
	 * The path to the file.
	 */
	private $path;
	
	/**
	 * A handle to manipulate the file.
	 *
	 * @var file handle
	 */
	private $handle;
	
	/**
	 * Constructs a new FileReference.
	 *
	 * @param string: $path the path to the file
	 */
	public function __construct($path) {
		$this->path = $path;
	}
	
	/**
	 * Gets the path to the file.
	 *
	 * @return the path to the file
	 */
	
	public function getPath() {
		return $this->path;
	}
	
	/**
	 * Tests whether this file is a directory or not.
	 *
	 * @return true when the file is a directory, false otherwise
	 */
	
	public function isDirectory() {
		return is_dir($this->path);
	}
	
	/**
	 * Gets the filename of the file. The filename is the part of the path
	 * after the last path separator. So the name for "/tmp/file1.txt" is 
	 * "file1.txt".
	 *
	 * @return the filename of the file
	 */
	
	public function getName() {
		return basename($this->path);
	}
	
	/**
	 * Tests whether the file can be written to or not.
	 *
	 * @return true when the file can be written to, false otherwise
	 */
	
	public function isWritable() {
		return is_writable($this->path);
	}
	
	/**
	 * Tests whether the file exists or not
	 *
	 * @return true when the file exists, false otherwise
	 */
	
	public function exists() {
		return file_exists($this->path);
	}
	
	/**
	 * Opens the file for writing. When a file is opened using open(), it should
	 * always be closed afterwards using close.
	 */
	
	public function open($mode = "r") {
		if ($writable = $this->isWritable() || !$this->exists()) {
		    $this->handle = fopen($this->path, $mode);
		    flock($this->handle, LOCK_EX);
		    if ($this->handle === null) {
		        throw new Pageley_Util_IoException("Failed to open file '" . $this->path . "'");
		    }
		} else {
		    throw new Pageley_Util_PermissionDeniedException("Failed to write to file '" . $this->path . "'.");
		}
	}
	
	/**
	 * Appends character data to the file.
	 *
	 * @param string $text: the character data to append to the file.
	 */
	public function write($text) {
		$opened = false;
		if($this->handle === null) {
			$this->open("a");
			$opened = true;
		}
		$result = fwrite($this->handle, $text);
	    if ($result === false) {
	        throw new Pageley_Util_IoException("Failed to write to file '" . $this->path . "'");
	    }
	    if($opened) {
	    	$this->close();
	    }
		
	}
	
	/**
	 * Closes the file and releases it.
	 */
	public function close() {
	    fclose($this->handle);
	    $this->handle = null;
	}
	
	public function read($length = 0) {
	    $opened = false;
        if($this->handle === null) {
            $this->open();
            $opened = true;
        }
		if($length == 0) {
			$length = $this->getSize();
		}
		$contents = fread($this->handle); 
	    if($opened) {
            $this->close();
        }
		return $contents;
	}
	
	/**
	 * Removes the file from the file system.
	 *
	 */
	public function delete() {
		unlink($this->path);
	}
	
	public function __toString() {
		return $this->path;
	}
	
	public function getParent() {
		return new Pageley_Util_Directory(dirname($this->path));
	}
	
	public function getExtension() {
		$name = $this->getName();
		$pos = Pageley_Util_String::lastIndexOf($name, ".");
		return Pageley_Util_String::substring($name, $pos);
	}
	
	public function getNameWithoutExtension() {
		$name = $this->getName();
		$nameLength = Pageley_Util_String::length($name);
		$extensionLength = Pageley_Util_String::length($this->getExtension());
		return Pageley_Util_String::substring($name, 0, $nameLength - $extensionLength);
	}
	
	public function getLastChanged() {
		return new Pageley_Util_Timestamp(filectime($this->path) * 1000);
	}
	
	public function getSize() {
		return filesize($this->path);
	}
}